Definimos inicialmente todos los paquetes que vamos necesitar para el trabajo.
La práctica se basará en los archivos de datos electorales que se indican a continuación, recopilando datos sobre las elecciones al Congreso de los Diputados en España desde 2008 hasta la actualidad, así como encuestas, códigos de municipios y abreviaturas
El trabajo consta de 4 bases de datos:
election_data: archivo con las elecciones al congresocod_mun: archivo con los códigos y nombres de cada municipioabbrev: siglas de cada partidosurveys: encuestas electorales desde 1982.election_data: archivo con las elecciones al congreso
tipo_eleccion: tipo de elecion (nacional, regional…)anno: Año de la eleccionmes: Mes de la eleccionvueltacodigo_ccaa: Código de la comunidad autónomacodigo_provincia:Código de la provinciacodigo_municipio: Código del municipiocodigo_distrito_electoral: Código del distritonumero_mesas: Número de mesas disponibleselection_data: archivo con las elecciones al congreso
censo: Número de personas del municipioparticipacion_1participacion_2votos_blancos: Cantidad de votos en blancovotos_nulos: Cantidad de votos nulosvotos_candidaturas: Cantidad de votos validossurveys: encuestas electorales desde 1982.
type_survey: tipo de encuesta (nacional, regional…)date_elec: fecha de las futuras eleccionesid_pollster, pollster, media: id y nombre de la empresa encuestadora, así como medio que la encargófield_date_from, field_date_to: fechas de inicio y fin del trabajo de la encuestaexit_poll: ¿es una encuesta a pie de urna?size: tamaño muestral de la encuestaturnout: participación (estimación)El objetivo de la entrega es realizar un análisis de los datos electorales, llevando a cabo la depuración, los resúmenes y los gráficos que consideres necesarios, tanto de los resultados como de la precisión de las encuestas electorales.
En concreto, debes trabajar únicamente en el período de tiempo que incluye las elecciones desde 2008 hasta las últimas elecciones de 2019
# Transforma los datos de surveys en tidydata
surveys_tidy <- surveys |>
pivot_longer( cols = "UCD":"EV",
names_to = "partidos",
values_to = "prob_votos",
values_drop_na = TRUE
)
# Transforma los datos de election_data en tidydata
election_data_tidy <- election_data |>
pivot_longer( cols = "BERDEAK-LOS VERDES":"COALICIÓN POR MELILLA",
names_to = "partidos",
values_to = "votos" ,
values_drop_na = TRUE
) |> unite(c("codigo_ccaa","codigo_provincia", "codigo_municipio"),col="cod_mun",sep='-')# Union de election_data_tidy con las siglas de los partidos y con los nombres de municipios
election_data_tidy <- election_data_tidy |>
left_join(abbrev, by = c("partidos" = "denominacion")) |>
left_join(cod_mun, by = c("cod_mun" = "cod_mun"))
# Union de surveys_tidy con las siglas de los partidos
surveys_tidy <- surveys_tidy |>
left_join(abbrev, by = c("partidos" = "siglas"))
surveys_tidy <- surveys_tidy |>
rename(siglas = partidos) # Cambiar "partidos" a "siglas"
surveys_tidy <- surveys_tidy |>
rename( partidos = denominacion) # Cambiar "denominacion" a "partidos"
# Verificar las uniones
head(surveys_tidy)
head(election_data_tidy)# Reagrupa los partidos de los datos "surveys_tidy"
surveys_tidy <- surveys_tidy |>
mutate(partidos = case_when(
str_detect(partidos,"SOCIALISTA") ~ "PSOE",
str_detect(partidos,"PARTIDO POPULAR") ~ "PP",
str_detect(partidos,"CIUDADANOS") ~ "CS",
str_detect(partidos,"VASCO") ~ "PNV",
str_detect(partidos,"BLOQUE NACIONALISTA GALEGO") ~ "BNG",
str_detect(partidos,"PODEMOS") ~ "UP",
str_detect(partidos,"ESQUERRA.*CATALUNYA|CATALUNYA.*ESQUERRA") ~ "ERC",
str_detect(partidos,"BILDU") ~ "EH - BILDU",
str_detect(partidos,"VOX") ~ "VOX",
TRUE ~ "OTROS"
))
head(surveys_tidy)
# Reagrupa los partidos de los datos "election_data_tidy"
election_data_tidy <- election_data_tidy |>
mutate(partidos = case_when(
str_detect(partidos,"SOCIALISTA") ~ "PSOE",
str_detect(partidos,"PARTIDO POPULAR") ~ "PP",
str_detect(partidos,"CIUDADANOS") ~ "CS",
str_detect(partidos,"VASCO") ~ "PNV",
str_detect(partidos,"BLOQUE NACIONALISTA GALEGO") ~ "BNG",
str_detect(partidos,"PODEMOS") ~ "UP",
str_detect(partidos,"ESQUERRA.*CATALUNYA|CATALUNYA.*ESQUERRA") ~ "ERC",
str_detect(partidos,"BILDU") ~ "EH - BILDU",
str_detect(partidos,"VOX") ~ "VOX",
TRUE ~ "OTROS"
))
election_data_tidySe aplicaron filtros a la base de datos inicial para cumplir con el objetivo del trabajo:
# Filtro aplicado en los datos de surveys_tidy
surveys_filtered <- surveys_tidy |>
mutate(date_elec = as.Date(date_elec, format = "%Y-%m-%d"), # paquete lubridate
field_date_to = as.Date(field_date_to, format = "%Y-%m-%d"),
field_date_from = as.Date(field_date_from, format = "%Y-%m-%d"),
ano_elec = year(date_elec), # paquete necesario lubridate
tiempo_trabajo_campo = as.numeric(field_date_to-field_date_from)) |>
filter(2008 >= ano_elec & ano_elec <= 2019
& exit_poll == FALSE
& (size >= 500 | !is.na(size))
& tiempo_trabajo_campo >= 1)
# Filtro aplicado en los datos de election_data_tidy
election_filtered <- election_data_tidy |>
filter(partidos %in% c('PSOE', 'PP', 'CS', 'PNV', 'BNG', 'UP', 'ERC', 'EH - BILDU', 'VOX' ))# Selecion previa de las variables
election_data_tidy_select <- election_filtered |>
select('anno', 'cod_mun', 'numero_mesas','censo', 'participacion_1', 'participacion_2', 'votos_blancos', 'votos_nulos','votos_candidaturas','partidos','votos')
surveys_tidy_select <- surveys_filtered |>
select('size', 'turnout', 'partidos', 'prob_votos', 'ano_elec','tiempo_trabajo_campo', 'id_pollster', 'pollster', 'media') |>
rename('tamano_muestra' = 'size',
'estimacion_participac' = 'turnout')
# Join
datos_election <- election_data_tidy_select |>
left_join(cod_mun, by = "cod_mun")# Agrupación de ganadores por año
ganadores_por_anno <- tabla_ganadores |>
group_by(anno, vencedor) |>
summarise(count = n(), .groups = "drop")
# Identificar los 3 partidos predominantes por número total de municipios ganados
partidos_predominantes <- ganadores_por_anno |>
group_by(vencedor) |>
summarise(total_municipios = sum(count), .groups = "drop") |>
arrange(desc(total_municipios)) |>
slice_head(n = 3) |>
pull(vencedor)
# Agrupar los partidos no predominantes como "OTROS"
ganadores_agrupados <- ganadores_por_anno |>
mutate(vencedor = ifelse(vencedor %in% partidos_predominantes, vencedor, "OTROS")) |>
group_by(anno, vencedor) |>
summarise(count = sum(count), .groups = "drop") # Sumar los valores de "OTROS"
# Graficar con los partidos agrupados
ggplot(ganadores_agrupados, aes(x = anno, y = count, fill = vencedor)) +
geom_bar(stat = "identity", position = "stack") +
geom_text(
aes(
label = paste0(count),
color = vencedor),
position = position_stack(vjust = 0.5), # Centra las etiquetas en las barras
size = 3,
color = "white"
) +
scale_x_continuous(breaks = unique(ganadores_agrupados$anno), # Etiquetas de años
labels = unique(ganadores_agrupados$anno)) +
scale_fill_manual(
values = c(
"VOX" = "#80b042",
"PP" = "#004a95",
"PSOE" = "#e30613",
"UP" = "#a668f3",
"CS" = "#ff956a",
"PNV" = "#917b66",
"ERC" = "#edc158",
"OTROS" = "gray"
)
) +
labs(
title = "Distribución de Partidos Ganadores por Año",
x = "Año",
y = "Número de Municipios",
fill = "Partido Ganador"
) +
theme_minimal() +
theme(
panel.background = element_rect(fill = "transparent", color = NA), # Fondo del panel transparente
plot.background = element_rect(fill = "transparent", color = NA), # Fondo general transparente
legend.background = element_rect(fill = "transparent", color = NA) # Fondo de la leyenda transparente
)Primero identificamos el partido ganador y el segundo partido genador en cada una de las elecciones
# Función para identificar el segundo partido cuando el primero es el especificado
partido_vencedor1 <- function(partido_venc) {
election_filtered |>
filter(censo > 100000) |> # Filtrar por municipios con más de 100,000 habitantes
group_by(anno,mes, municipio) |> # Agrupar por año y municipio
arrange(desc(votos)) |> # Ordenar por número de votos en orden descendente
mutate(posicion = row_number()) |> # Asignar posición (1 = primero, 2 = segundo)
summarise(
primero_partido = partidos[posicion == 1], # Partido ganador
segundo_partido = partidos[posicion == 2], # Partido en segundo lugar
.groups = "drop"
) |>
filter(primero_partido == partido_venc) # Filtrar para que el partido ganador sea el especificado
}
# Obtener resultados cuando el primero es PSOE
resultados_psoe <- partido_vencedor1("PSOE")
# Obtener resultados cuando el primero es PP
resultados_pp <- partido_vencedor1("PP")
# Mostrar los resultados
resultados_psoe
resultados_ppPosteriormente sobre el mismo código eliminamos los municipios en los que el partido ganador y el segundo ganador es el mismo
partido_vencedor <- function(partido_venc) {
election_filtered |>
filter(censo > 100000) |> # Filtrar por municipios con más de 100,000 habitantes
group_by(anno, mes, municipio) |> # Agrupar por año, mes y municipio
arrange(desc(votos)) |> # Ordenar por número de votos en orden descendente
mutate(posicion = row_number()) |> # Asignar posición (1 = primero, 2 = segundo, etc.)
filter(
(posicion == 1 & partidos == partido_venc) | # Mantener el ganador que corresponde al filtro
(posicion == 2 & partidos != partido_venc) # Asegurar que el segundo partido sea diferente al ganador
) |>
reframe(
primero_partido = partidos[posicion == 1],
segundo_partido = partidos[posicion == 2],
anno = unique(anno), # Asegurar que el año se incluya
mes = unique(mes),
municipio = unique(municipio)
)
}
# Obtener resultados cuando el primero es PSOE
resultados_psoe <- partido_vencedor("PSOE")
# Obtener resultados cuando el primero es PP
resultados_pp <- partido_vencedor("PP")
# Mostrar los resultados ajustados
resultados_psoe
resultados_pplibrary(ggplot2)
# Crear un dataset combinado para ambos casos (PSOE y PP)
resultados_psoe <- partido_vencedor("PSOE") |> mutate(ganador = "PSOE")
resultados_pp <- partido_vencedor("PP") |> mutate(ganador = "PP")
resultados_comb <- bind_rows(resultados_psoe, resultados_pp)
# Gráfico de barras apiladas
ggplot(resultados_comb, aes(x = ganador, fill = segundo_partido)) +
geom_bar() +
scale_fill_manual(
values = c(
"VOX" = "#80b042",
"PP" = "#004a95",
"PSOE" = "#e30613",
"UP" = "#a668f3",
"CS" = "#ff956a",
"PNV" = "#917b66",
"ERC" = "#edc158",
"OTROS" = "gray"
)
) +
labs(
title = "Distribución de Segundos Partidos por Partido Ganador",
x = "Partido Ganador",
y = "Número de Municipios",
fill = "Segundo Partido"
) +
theme_minimal()# Función para calibrar el error y generar tablas de salida
calibrar_error <- function(election_data, surveys) {
# Preparación de los datos de las elecciones: cálculo del porcentaje real de votos
election_data_grouped <- election_data |>
group_by(anno, partidos) |>
summarise(
actual_votes = sum(votos, na.rm = TRUE), # Total de votos por partido
total_votes = sum(votos_candidaturas, na.rm = TRUE), # Total de votos válidos
.groups = "drop"
) |>
mutate(
actual_share_percent = (actual_votes / total_votes) * 100 # Porcentaje real de votos
)
# Vincular encuestas con resultados reales
datos_combinados <- surveys |>
inner_join(election_data_grouped,
by = c("ano_elec" = "anno", "partidos" = "partidos")) |>
mutate(
error = prob_votos - actual_share_percent # Error: diferencia entre encuesta y resultado real
)
# Crear tabla con porcentajes
tabla_procentajes <- datos_combinados |>
select(
ano_elec, partidos, prob_votos, actual_share_percent, error
)
# Análisis del error: promedio y desviación estándar por partido
errores <- datos_combinados |>
group_by(partidos) |>
summarise(
mean_error = mean(error, na.rm = TRUE), # Error promedio
sd_error = sd(error, na.rm = TRUE), # Desviación estándar del error
n = n(), # Número de observaciones
.groups = "drop"
)
list(
tabla_procentajes = tabla_procentajes, # Tabla con porcentajes
errores = errores # Estadísticas del error
)
}
# Aplicar la función a los conjuntos de datos para todos los años
resultados <- calibrar_error(election_data_tidy_select, surveys_tidy_select)
# Resultados
tabla_procentajes <- resultados$tabla_procentajes # Tabla con porcentajes estimados y reales
errores <- resultados$errores # Estadísticas del error
# Mostrar las tablas
print(tabla_procentajes) # Vista previa de la tabla con porcentajes# A tibble: 567 × 5
ano_elec partidos prob_votos actual_share_percent error
<dbl> <chr> <dbl> <dbl> <dbl>
1 2008 PSOE 43.4 35.1 8.34
2 2008 PNV 6 27.6 -21.6
3 2008 ERC 4 7.23 -3.23
4 2008 PP 38.1 41.8 -3.70
5 2008 PSOE 43 35.1 7.94
6 2008 PNV 6 27.6 -21.6
7 2008 ERC 5 7.23 -2.23
8 2008 PP 39 41.8 -2.80
9 2008 PSOE 42.6 35.1 7.54
10 2008 PNV 6 27.6 -21.6
# ℹ 557 more rows
# A tibble: 5 × 4
partidos mean_error sd_error n
<chr> <dbl> <dbl> <int>
1 BNG -11.0 0.641 15
2 ERC -4.81 1.23 103
3 PNV -25.8 1.15 109
4 PP -3.37 1.46 170
5 PSOE 7.21 1.69 170
Siguiendo la clasificación establecida por el Ministerio de Agricultura y Pesca de España, se definen las zonas de la siguiente manera:
Con base en esta clasificación, hemos creado la variable “tipo_zona” como paso previo al análisis.
distribucion_voto <- election_filtered |>
mutate(tipo_zona = case_when(
censo < 2000 ~ "Rural",
censo >= 2000 & censo <= 10000 ~ "Semiurbano",
censo > 10000 ~ "Urbano"
)) |>
mutate(partidos = as_factor(partidos),
tipo_zona = factor(tipo_zona,
levels = c("Rural", "Semiurbano", "Urbano"),
ordered = TRUE))
# Agrupación por tipo de zona y partidos
porc_distribucion_voto <- distribucion_voto |>
group_by(tipo_zona) |>
mutate(total_votos_zona = sum(votos, na.rm = TRUE)) |>
group_by(tipo_zona, partidos) |>
summarise(
total_votos_partido = sum(votos, na.rm = TRUE),
porcentaje_votos = (total_votos_partido / total_votos_zona[1]) * 100,
.groups = "drop"
)
# Ver el resultado
porc_distribucion_votoggplot(porc_distribucion_voto, aes(x = tipo_zona, y = porcentaje_votos, fill = partidos)) +
geom_bar(stat = "identity", position = "fill") +
geom_text(
aes(
label = paste0(round(porcentaje_votos, 1), "%")
),
position = position_fill(vjust = 0.5), # Centra las etiquetas en las barras
size = 3,
color = "white"
) +
scale_fill_manual(
values = c(
"VOX" = "#80b042",
"PP" = "#004a95",
"PSOE" = "#e30613",
"UP" = "#a668f3",
"CS" = "#ff956a",
"PNV" = "#917b66",
"ERC" = "#edc158",
"OTROS" = "gray"
)
) +
labs(
title = "Distribución de votos por tipo de zona",
x = "Tipo de zona",
y = "Porcentaje de votos (%)",
fill = "Partidos"
) +
scale_y_continuous(labels = scales::percent_format(scale = 100)) +
theme_minimal()Si los votos (votos) son valores numéricos y deseas analizar si las medias de votos difieren significativamente entre tipos de zona para cada partido, puedes usar ANOVA.
# Crear tabla de contingencia
tabla_contingencia <- distribucion_voto |>
group_by(tipo_zona, partidos) |>
summarise(
total_votos = sum(votos, na.rm = TRUE),
.groups = "drop"
) |>
pivot_wider(
names_from = partidos,
values_from = total_votos,
values_fill = 0
)
# Convertir a matriz para el test de Chi-cuadrado
matriz_contingencia <- as.matrix(tabla_contingencia[, -1]) # Eliminar la columna 'tipo_zona'
# Realizar el test de Chi-cuadrado
test_chi2 <- chisq.test(matriz_contingencia)
# Resultados del test
print(test_chi2)
Pearson's Chi-squared test
data: matriz_contingencia
X-squared = 1817609, df = 16, p-value < 2.2e-16
PSOE PP PNV CS ERC BNG UP
[1,] 459.0905 296.12411 -58.04050 -545.0381 204.5296 -150.3846 -578.8896
[2,] 455.4392 -39.68112 157.53899 -441.0966 184.7465 387.1418 -405.6246
[3,] -690.5662 -157.70441 -98.31582 733.9006 -291.9876 -236.5788 725.2347
EH - BILDU VOX
[1,] 178.2018 -145.2666
[2,] 226.5804 -104.1849
[3,] -311.0199 184.0592
El análisis confirma que existe una relación estadísticamente significativa entre el tipo de zona y el voto a un partido político. Esto sugiere que ciertos partidos tienen más apoyo en zonas rurales, semiurbanas o urbanas, y que este patrón es consistente.
NO ME FUNCIONA ME QUEDO POR AQUI PREGUNTAR A CHAT GPT POR Análisis de correlación entre el censo poblacional y el porcentaje de votos por partido
# Reordenando los partidos
datos_distribucion_voto <-
distribucion_voto |>
mutate("median_votos" = median(votos), .by = c(tipo_zona,partidos)) |>
mutate("partidos" = fct_reorder(partidos, median_votos))
# Remover outliers usando a regra do IQR
q1 <- quantile(datos_distribucion_voto$votos, 0.25)
q3 <- quantile(datos_distribucion_voto$votos, 0.75)
iqr <- q3 - q1
# Filtrando os dados para remover outliers
datos_election_clean <- datos_distribucion_voto |>
filter(votos >= (q1 - 1.5 * iqr) & votos <= (q3 + 1.5 * iqr))# boxplot
ggplot(datos_election_clean) +
geom_boxplot(aes(x = partidos, y = votos, fill = median_votos ),
alpha = 0.5) +
scale_fill_gradient2(low = "red", mid = "white", high = "green",
midpoint = 2000) +
facet_wrap(~tipo_zona,scales = "free_y") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90))El Partido Popular (PP) y el Partido Socialista Obrero Español (PSOE) dominan en participación acumulada, con líneas más destacadas y continuas en todos los periodos.
Otros partidos como ERC, PNV y UP muestran una participación más estable y con menos variabilidad.
Vox y Ciudadanos (CS) tienen líneas menos pronunciadas, indicando que su impacto es menor en municipios grandes.
El año más reciente (probablemente 2019) muestra un aumento drástico en participación para los municipios donde ganó el PSOE.
Esto sugiere que, aunque el PP mantiene una base de participación estable, el PSOE ha conseguido movilizar a más votantes recientemente.
# Filtrar municipios con más de 50.000 habitantes
municipios_grandes <- datos_election |>
filter(censo > 50000)
# Calcular la suma de participación y votos por municipio y año
participacion_municipios <- municipios_grandes |>
group_by(anno, cod_mun, municipio) |>
summarise(
participacion_1 = sum(participacion_1),
participacion_2 = sum(participacion_2),
votos_totales = sum(votos),
partido_ganador = partidos[which.max(votos)]
) |>
ungroup()# Visualizar la evolución de la participación por partido
ggplot(participacion_municipios, aes(x = anno, y = participacion_1, color = partido_ganador)) +
geom_line() +
geom_point() +
labs(
title = "Evolución de la Participación en Municipios con Más de 50.000 Habitantes",
x = "Año",
y = "Participación (Primera Vuelta)",
color = "Partido Ganador"
) +
theme_minimal()# Filtrar el año más reciente
anio_reciente <- max(datos_election$anno)
# Filtrar datos del año más reciente
datos_recientes <- datos_election |>
filter(anno == anio_reciente)
# Determinar el partido más votado por municipio
partido_ganador_municipio <- datos_recientes |>
group_by(municipio) |>
summarise(partido_ganador = partidos[which.max(votos)]) |>
ungroup()
# Mostrar resultados
print(partido_ganador_municipio)# A tibble: 8,114 × 2
municipio partido_ganador
<chr> <chr>
1 Ababuj PP
2 Abades PP
3 Abadiño PNV
4 Abadía PSOE
5 Abadín PP
6 Abajas PSOE
7 Abaltzisketa PNV
8 Abanilla PP
9 Abanto PP
10 Abanto y Ciérvana-Abanto Zierbena PNV
# ℹ 8,104 more rows